package com.platform.core.security.auth;

import com.google.common.base.Strings;
import com.platform.comm.config.properties.JwtProperties;
import com.platform.comm.jwt.JwtTokenUtil;
import com.platform.comm.util.CommonWriter;
import com.platform.comm.web.results.JsonResult;
import com.platform.config.properties.CustomSecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Nonnull;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.platform.comm.constants.RespCode.FAILED;
import static com.platform.comm.constants.RespCode.TOKEN_MISMATCH;
import static com.platform.core.utils.RequestUtil.matchesUrls;


/**
 * @author sunzhubin.zh
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    private final JwtTokenUtil jwtTokenUtil;
    private final JwtProperties jwtProperties;
    private final CustomSecurityProperties securityProperties;

    @Autowired
    public JwtAuthenticationTokenFilter(JwtTokenUtil jwtTokenUtil,
                                        JwtProperties jwtProperties, CustomSecurityProperties securityProperties) {
        this.jwtTokenUtil = jwtTokenUtil;
        this.jwtProperties = jwtProperties;
        this.securityProperties = securityProperties;
    }

    @Override
    protected void doFilterInternal(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response,
                                    @Nonnull FilterChain chain) throws ServletException, IOException {
        JsonResult result = JsonResult.of();
        String authorization = request.getHeader(jwtProperties.getHeader());
        if (!matchesUrls(securityProperties.getPermitAll(), request)) {
            if (Strings.isNullOrEmpty(authorization)) {
                CommonWriter.write(result.apply(FAILED, "未提供认证信息"), response);
                return;
            }
            if (!authorization.startsWith(jwtProperties.getTokenHead())) {
                CommonWriter.write(result.apply(FAILED, "认证信息格式错误"), response);
                return;
            }
            final String token = authorization.replace(jwtProperties.getTokenHead(), "");
            JwtTokenUtil.JwtUser userDetails = jwtTokenUtil.getUserFromToken(token);
            if (Objects.isNull(userDetails)) {
                CommonWriter.write(result.apply(FAILED, "无效的认证信息"), response);
                return;
            }
            if (jwtTokenUtil.validateToken(token, userDetails)) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
                        token, Arrays
                        .stream(userDetails.getAuth().split(","))
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toList()));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } else {
                CommonWriter.write(result.apply(FAILED, "认证信息已过期"), response);
                return;
            }
        }
        chain.doFilter(request, response);
    }
}
